package seckillx

import (
	"net/http"
	"os"
	"strconv"
	"strings"

	"github.com/garyburd/redigo/redis"
	"github.com/zeromicro/go-zero/core/logx"
)

// 在启动服务之前，我们需要初始化redis的初始库存信息:
// hmset ticket_hash_key "ticket_total_nums" 10000 "ticket_sold_nums" 0
// 
// 开启服务，我们使用ab压测工具进行测试：
// ab -n 10000 -c 100 http://127.0.0.1:3005/buy/ticket

func buy() {
	// 初始化要使用的结构体和redis连接池
	// service
	localSpike := LocalSpike{
		LocalInStock:     150,
		LocalSalesVolume: 0,
	}
	remoteSpike := RemoteSpikeKeys{
		SpikeOrderHashKey:  "ticket_hash_key",
		TotalInventoryKey:  "ticket_total_nums",
		QuantityOfOrderKey: "ticket_sold_nums",
	}
	redisPool := NewPool()
	var done chan int
	done = make(chan int, 1)
	done <- 1

	// 处理请求函数, 根据请求将响应结果信息写入日志
	// handler
	redisConn := redisPool.Get()
	LogMsg := ""
	<-done
	// 全局读写锁
	if localSpike.LocalDeductionStock() && remoteSpike.RemoteDeductionStock(redisConn) {
		logx.Info("抢票成功")
		LogMsg = LogMsg + "result:1,localSales:" + strconv.FormatInt(localSpike.LocalSalesVolume, 10)
	} else {
		logx.Error("已售罄")
		LogMsg = LogMsg + "result:0,localSales:" + strconv.FormatInt(localSpike.LocalSalesVolume, 10)
	}
	// 将抢票状态写入到log中
	done <- 1
	writeLog(LogMsg, "./stat.log")
}

func writeLog(msg string, logPath string) {
	fd, _ := os.OpenFile(logPath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
	defer fd.Close()
	content := strings.Join([]string{msg, "\r\n"}, "")
	buf := []byte(content)
	fd.Write(buf)
}



// https://github.com/GuoZhaoran/spikeSystem

/**
#配置负载均衡
    upstream load_rule {
       server 127.0.0.1:3001 weight=1;
       server 127.0.0.1:3002 weight=2;
       server 127.0.0.1:3003 weight=3;
       server 127.0.0.1:3004 weight=4;
    }
    ...
    server {
    listen       80;
    server_name  load_balance.com www.load_balance.com;
    location / {
       proxy_pass http://load_rule;
    }
}
 */

/*
2.3 预扣库存
  先扣除了库存，保证不超卖，然后异步生成用户订单，这样响应给用户的速度就会快很多；
  那么怎么保证不少卖呢？用户拿到了订单，不支付怎么办？我们都知道现在订单都有有效期，比如说用户五分钟内不支付，订单就失效了，订单一旦失效，就会加入新的库存，这也是现在很多网上零售企业保证商品不少卖采用的方案。
  订单的生成是异步的,一般都会放到MQ、kafka这样的即时消费队列中处理,订单量比较少的情况下，生成订单非常快，用户几乎不用排队。
3. 扣库存的艺术
  接下来我们对单机扣库存的方案做优化：本地扣库存。我们把一定的库存量分配到本地机器，直接在内存中减库存，然后按照之前的逻辑异步创建订单。
  高并发情况下，现在我们还无法保证系统的高可用，假如这100台服务器上有两三台机器因为扛不住并发的流量或者其他的原因宕机了。那么这些服务器上的订单就卖不出去了，这就造成了订单的少卖。
  要解决这个问题，我们需要对总订单量做统一的管理，这就是接下来的容错方案。服务器不仅要在本地减库存，另外要远程统一减库存。有了远程统一减库存的操作，我们就可以根据机器负载情况，为每台机器分配一些多余的“buffer库存”用来防止机器中有机器宕机的情况。
  buffer余票设置多少合适呢，理论上buffer设置的越多，系统容忍宕机的机器数量就越多，但是buffer设置的太大也会对redis造成一定的影响。(库存=总库存/实例数、buffer库存=库存/3)
 */
